package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;

import com.zzyl.dto.LoginDto;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;
    /**
     * 分页查询
     * @param userDto
     * @param pageSize
     * @param pageNum
     * @return
     */
    @Override
    public PageResponse<UserVo> selectPage(UserDto userDto, Integer pageSize, Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);

        List<UserVo> list = userMapper.selectPage(userDto);
//        上面的UserVo缺少roleVoIds和roleLabels
//        list.forEach(userVo -> {
//            List<Long> roleId = userRoleMapper.selectRoleId(userVo.getId());
//            //类型转换 把List<Long>转换成List<String>
//            List<String> roleIds = roleId.stream()
//                    .map(String::valueOf)
//                    .collect(Collectors.toList());
//
//            //再转换成Set
//            HashSet<String> roleSet = new HashSet<>(roleIds);
//            userVo.setRoleVoIds(roleSet);
//        });
        Page<UserVo> page = (Page<UserVo>)list;

        return PageResponse.of(page,UserVo.class);
    }

    /**
     * 新增用户
     * @param userDto
     */
    @Override
    @Transactional
    public void insert(UserDto userDto) {
        User user = BeanUtil.toBean(userDto, User.class);
        //1.完成User表基本数据的新增 非空字段的补充
        user.setCreateTime(LocalDateTime.now());
        user.setCreateBy(1L);
        //初始密码需要加密
        user.setPassword(BCrypt.hashpw("123456", BCrypt.gensalt()));
        user.setDataState(SuperConstant.DATA_STATE_0);

        userMapper.insert(user);

        //2.完成User-role中间表的新增前需要把拿到的数组转换成List集合
        Set<String> roleVoIds = userDto.getRoleVoIds();
        List<String> roleIdList = new ArrayList<>(roleVoIds);

        //声明一个List<UserRole>用户和角色的中间表集合
//        List<UserRole> userRoleList = new ArrayList<>();

        //完成userRoleList的构建
        List<UserRole> userRoleList = roleIdList.stream().map(roleId -> {
            //创建一个UserRole实体对象
            UserRole userRole = new UserRole();
            //补充缺少字段
            userRole.setUserId(user.getId());
            userRole.setRoleId(Long.parseLong(roleId));
            userRole.setDataState(SuperConstant.DATA_STATE_0);
            userRole.setCreateTime(LocalDateTime.now());
            userRole.setCreateBy(1L);
//
//            userRoleList.add(userRole);
            return userRole;
        }).collect(Collectors.toList());


        //批量新增中间表
        userRoleMapper.insertBatch(userRoleList);
    }

    /**
     * 修改用户
     * 1.先对user表更新 再对userRole表先删除再insertBatch 和新增的逻辑完全一致
     * @param userDto
     */
    @Override
    @Transactional
    public void update(UserDto userDto) {
        //1.完成对user表的更新
        User user = BeanUtil.toBean(userDto, User.class);
        //字段补充
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateBy(1L);
        //user表基本信息的更新
        userMapper.update(user);

        //2.完成对userRole中间的更新 更新前先删除已有的中间表 再新增新的中间表
        userRoleMapper.deleteByUserId(userDto.getId());

        Set<String> roleVoIds = userDto.getRoleVoIds();
        List<String> roleIdList = new ArrayList<>(roleVoIds);

        //声明一个List<UserRole>用户和角色的中间表集合
        List<UserRole> userRoleList = new ArrayList<>();
        roleIdList.stream().map(roleId ->{
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(Long.parseLong(roleId));
            userRole.setDataState(SuperConstant.DATA_STATE_0);
            userRole.setCreateTime(LocalDateTime.now());
            userRole.setCreateBy(1L);

            userRoleList.add(userRole);
            return userRoleList;
        }).collect(Collectors.toList());


        //批量新增中间表
        userRoleMapper.insertBatch(userRoleList);
    }

    /**
     * 启用或者禁用
     * @param id
     * @param status
     */
    @Override
    public void startOrStop(Long id, String status) {
        //字段的补充 Integer Id需要转换为Long
        User user = new User();
        user.setId(id);
        user.setDataState(status);
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateBy(1L);

        userMapper.update(user);
    }

    /**
     * 根据Id删除
     * 点击【删除】，若该用户状态=启用，出错误提示：启用状态下不可删除；
     * 若用户状态=禁用，点击【删除】，出【确认删除】弹窗，点击【确定】后，该用户数据从列表中移除
     * 删除用户数据时，只从列表中移除数据，不从数据库中删除该用户信息；
     * 例如：该用户创建过数据，创建人依然显示该用户名称；若创建同名用户，则提示操作失败，数据重复；
     * @param userId
     */
    @Override
    public void deleteById(Long userId) {
        //校验用户状态是否为启用 如果为启用不可删除且抛出异常
        User user = userMapper.getById(userId);
        if (user !=null && user.getDataState().equals(SuperConstant.DATA_STATE_0)) {
            throw new BaseException(BasicEnum.USER_DISTRIBUTED);
        }
        user.setIsDelete(Integer.parseInt(SuperConstant.DATA_STATE_1));

        //执行更新 不执行删除
        // TODO 为什么逻辑禁用后前端还是能显示出来信息 并且 新增还需要补充校验
        userMapper.update(user);
    }

    /**
     * 重置该用户密码
     * @param userId
     * @return
     */
    @Override
    public boolean resetPassword(Long userId) {
        User user = userMapper.getById(userId);
        user.setPassword(BCrypt.hashpw("123456", BCrypt.gensalt()));
        user.setUpdateTime(LocalDateTime.now());
        user.setUpdateBy(1L);

        userMapper.update(user);
        // TODO 懒得修改更新Mapper的返回值类型了
        return true;
    }



}
